﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.ComponentModel;
using System.Collections;

namespace ZKChartLibrary
{
    /// <summary>
    /// ZKChartUserControl.xaml 的交互逻辑
    /// </summary>
    public enum CHART_MODE
    {
        CONTINUITY_MODE, BLOCK_MODE
    }
    public partial class ZKChartUserControl : UserControl
    {

        private List<ChartData> chDataList = null;
        private DispatcherTimer dispatcherTimer;
        private int yMinData;
        private int yMaxData;
        private bool bEnter = false;
        private ArrayList minmaxList = new ArrayList();
        
        #region 下方成员变量与放大缩小相关
        private bool bClick = false;
        System.Windows.Shapes.Rectangle chartRectangle;
        System.Windows.Point StartPoint;
        private int yLastMin;
        private int yLastMax;
        private int xLastMin;
        private int xLastMax;
        #endregion

        public ZKChartUserControl()
        {
            InitializeComponent();
            dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, FreshTime); // 300ms刷新一次
            if(Start)
                dispatcherTimer.Start();
            //DataContext = this;                                 // 设定相应XMAL的上下文
            xMinNumericCtrl.DataContext = this;
            xMaxNumericCtrl.DataContext = this;
            yMinNumericCtrl.DataContext = this;
            yMaxNumericCtrl.DataContext = this;
            AutoCheckBox.DataContext = this;
            GridCheckBox.DataContext = this;
            HeadString.DataContext = this;
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            // do something here...
            DrawCurve(Auto,false);
        }

        private void OnChartSizeChanged(object sender, SizeChangedEventArgs e)
        {
            DrawCurve(Auto,false);
        }

        #region 与放大缩小相关
        private void OnChartLeftMouseButtonDown(object sender, MouseButtonEventArgs e)
        {
            //MessageBox.Show("hello");
            if (Start)
                return;
            bClick = true;
            yLastMin = yMin;
            yLastMax = yMax;
            xLastMin = xMin;
            xLastMax = xMax;
            chartRectangle = new System.Windows.Shapes.Rectangle() { Fill = new SolidColorBrush(), Stroke = System.Windows.Media.Brushes.Black, StrokeThickness = 1 };
            chartRectangle.Opacity = 1;
            StartPoint = e.GetPosition((sender as Canvas));
            Canvas.SetLeft(chartRectangle, StartPoint.X);
            Canvas.SetTop(chartRectangle, StartPoint.Y);
            (sender as Canvas).Children.Add(chartRectangle);
        }

        private void OnChartMouseMove(object sender, MouseEventArgs e)
        {
            if (Start)
                return;
            if (bClick == false)
                return;
            System.Windows.Point chartEndPoint = e.GetPosition((sender as Canvas));
            if (chartEndPoint.X > StartPoint.X)
            {
                chartRectangle.Width = chartEndPoint.X - StartPoint.X;
            }
            else
            {
                chartRectangle.Width = StartPoint.X - chartEndPoint.X;
                Canvas.SetLeft(chartRectangle, chartEndPoint.X);
            }

            if (chartEndPoint.Y > StartPoint.Y)
            {
                chartRectangle.Height = chartEndPoint.Y - StartPoint.Y;
            }
            else
            {
                chartRectangle.Height = StartPoint.Y - chartEndPoint.Y;
                Canvas.SetTop(chartRectangle, chartEndPoint.Y);
            }
        }

        private void OnChartLeftMouseButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (Start)
                return;
            bClick = false;
            System.Windows.Point EndPoint = e.GetPosition((sender as Canvas));
            (sender as Canvas).Children.Remove(chartRectangle);

            // x轴起始下标
            int width = xMax - xMin;
            int startTemp = xMin;

            xMin = (int)Math.Ceiling(StartPoint.X / (sender as Canvas).ActualWidth * width + startTemp);

            // x轴结束下标
            //if (chartEndPoint.X - leftmargin > 0)
            xMax = (int)Math.Floor(EndPoint.X / (sender as Canvas).ActualWidth * width + startTemp);
            //if (xMax - xMin < 1)
            //{//恢复原样
            //    xMin = xLastMin;
            //    xMax = xLastMax;
            //    yMin = yLastMin;
            //    yMax = yLastMax;
            //}
            //else
            //    EnergyChartAuto.isAuto = true;
            int hight = yMax - yMin;
            double ey = hight / (sender as Canvas).ActualHeight; // 每个刻度高度
            double e0 = (sender as Canvas).ActualHeight; // y轴最底部
            int mintemp = yMin;
            //if (hight > 0)
            //{
            yMin = StartPoint.Y > EndPoint.Y ? (int)((e0 - StartPoint.Y) * ey + mintemp) : (int)((e0 - EndPoint.Y) * ey + mintemp);
            yMax = StartPoint.Y > EndPoint.Y ? (int)((e0 - EndPoint.Y) * ey + mintemp) : (int)((e0 - StartPoint.Y) * ey + mintemp);
            //if (yMax - yMin < 1)
            //{//恢复原样
            //    xMin = xLastMin;
            //    xMax = xLastMax;
            //    yMin = yLastMin;
            //    yMax = yLastMax;
            //}

            //}
            DrawCurve(Auto,true);

        }
        #endregion

        public int AddNewLine(ChartData cd)
        {
            if (chDataList == null)
                chDataList = new List<ChartData>();
            chDataList.Add(cd);
            return chDataList.Count-1; // 返回所在位置index
        }

        public bool AddData(int index, int v)
        {
            bool bQuit = false;
            Dispatcher.Invoke(
                    (Action)(() =>
                    {
                        if (!Start)
                        { bQuit = true; }
                    })
                  );
            if (bQuit)
                return false;// 没启动，立即退出

            if (chDataList == null)
                return false;
            if (index >= chDataList.Count)
                return false;
            
            chDataList[index].dotlist.Add(v);
            // 计算最小最大值
            if (chDataList[index].isDraw)
            {
                if (!bEnter)
                {
                    yMinData = v;
                    yMaxData = v;
                    bEnter = true;
                }
                else
                {
                    if (v < yMinData)
                        yMinData = v;
                    if (v > yMaxData)
                        yMaxData = v;
                }
            }
            Dispatcher.Invoke(
                              (Action)(() =>
                              {
                                  if (Auto)
                                  {//如果自动，则自动调整yMin和yMax
                                      yMin = yMinData;
                                      yMax = yMaxData;
                                  }
                               })
      );

            return true;
        }

        public bool SetIsDraw(int index, bool bdraw)
        {
            if (chDataList == null)
                return false;
            if (index >= chDataList.Count)
                return false;

            chDataList[index].isDraw = bdraw;

            return true;
        }

        public void ClearAll()
        {
            if (chDataList != null)
            {
                for(int i=0;i<chDataList.Count;i++)
                    chDataList[i].dotlist.Clear();
            }
            bEnter = false;
        }

        public ChartData GetLine(int index)
        {
            if (chDataList == null)
                return null;
            if (index >= chDataList.Count)
                return null;
            return chDataList[index];
        }

        #region Start
        public bool Start
        {
            get { return (bool)GetValue(StartProperty); }
            set { SetValue(StartProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Start.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StartProperty =
            DependencyProperty.Register("Start", typeof(bool), typeof(ZKChartUserControl), new PropertyMetadata(false,StartPropertyChangedCallback));

        private static void StartPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue == true)
            {
                if ((d as ZKChartUserControl).ChartMode == CHART_MODE.CONTINUITY_MODE)
                {// 如果是Continue模式，那么xMin自动调整为0;
                    (d as ZKChartUserControl).xMin = 0;
                    (d as ZKChartUserControl).xMinLabel.IsEnabled = false;
                    (d as ZKChartUserControl).xMinNumericCtrl.IsEnabled = false;
                }

                (d as ZKChartUserControl).dispatcherTimer.Start();
            }
            else
            {
                if ((d as ZKChartUserControl).ChartMode == CHART_MODE.CONTINUITY_MODE)
                { 
                    (d as ZKChartUserControl).xMinLabel.IsEnabled = true;
                    (d as ZKChartUserControl).xMinNumericCtrl.IsEnabled = true;
                }
                (d as ZKChartUserControl).dispatcherTimer.Stop();
            }
        }

        #endregion

        #region FreshTime
        public int FreshTime
        {
            get 
            { 
                return (int)GetValue(FreshTimeProperty); 
            }
            set 
            { 
                SetValue(FreshTimeProperty, value);
                //NotifyPropertyChanged("FreshTime");
            }
        }

        // Using a DependencyProperty as the backing store for FreshTime.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FreshTimeProperty = 
            DependencyProperty.Register("FreshTime", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(300,FreshTimePropertyChangedCallback,null));

        private static void FreshTimePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var newtime = (int)e.NewValue;
            //MessageBox.Show("sss");
            (d as ZKChartUserControl).dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, newtime ); // 300ms刷新一次
            if ((d as ZKChartUserControl).Start)
                (d as ZKChartUserControl).dispatcherTimer.Start();
        }
        #endregion

        #region xMax
        public int xMax
        {
            get { return (int)GetValue(xMaxProperty); }
            set { 
                SetValue(xMaxProperty, value);
                //NotifyPropertyChanged("xMax");
            }
        }

        // Using a DependencyProperty as the backing store for xMax.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty xMaxProperty =
            DependencyProperty.Register("xMax", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(100, xMaxPropertyChangedCallback, xMaxPropertyCoerceValueCallback));

        private static void xMaxPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //MessageBox.Show("adbc");
            d.CoerceValue(xMaxProperty);
            //d.CoerceValue(xScaleProperty);
            DrawXscale(d as ZKChartUserControl);
            DrawX(d as ZKChartUserControl);
            //if (!(d as ZKChartUserControl).Start)
            //{
            //    (d as ZKChartUserControl).DrawCurve((d as ZKChartUserControl).Auto, true);
            //}
        }
        private static object xMaxPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            if (v < (d as ZKChartUserControl).xMin)
                v = (d as ZKChartUserControl).xMin;
            return v;
        }
        #endregion

        #region xMin
        public int xMin
        {
            get { return (int)GetValue(xMinProperty); }
            set { 
                SetValue(xMinProperty, value);
                //NotifyPropertyChanged("xMin");
            }
        }

        // Using a DependencyProperty as the backing store for xMax.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty xMinProperty =
            DependencyProperty.Register("xMin", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(0, xMinPropertyChangedCallback, xMinPropertyCoerceValueCallback));

        private static void xMinPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(xMinProperty);
            DrawXscale(d as ZKChartUserControl);
            DrawX(d as ZKChartUserControl);
            //if (!(d as ZKChartUserControl).Start)
            //{
            //    (d as ZKChartUserControl).DrawCurve((d as ZKChartUserControl).Auto, true);
            //}
        }

        private static object xMinPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            if (v < 0) // xMin不能小于0
                v = 0;
            if (v > (d as ZKChartUserControl).xMax)
                v = (d as ZKChartUserControl).xMax;
            return v;
        }
        #endregion

        #region yMax
        public int yMax
        {
            get { return (int)GetValue(yMaxProperty); }
            set { 
                SetValue(yMaxProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for xMax.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty yMaxProperty =
            DependencyProperty.Register("yMax", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(32767, yMaxPropertyChangedCallback, yMaxPropertyCoerceValueCallback));

        private static void yMaxPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //MessageBox.Show("adbc");
            d.CoerceValue(yMaxProperty);
            DrawYscale(d as ZKChartUserControl);
            DrawY(d as ZKChartUserControl);
            //if (!(d as ZKChartUserControl).Start)
            //{
            //    (d as ZKChartUserControl).DrawCurve((d as ZKChartUserControl).Auto, true);
            //}
        }

        private static object yMaxPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            if (v > Int16.MaxValue)
                v = Int16.MaxValue;
            if (v < Int16.MinValue)
                v = Int16.MinValue;
            if (v < (d as ZKChartUserControl).yMin)
                v = (d as ZKChartUserControl).yMin;
            return v;
        }
        #endregion

        #region yMin
        public int yMin
        {
            get { return (int)GetValue(yMinProperty); }
            set { 
                SetValue(yMinProperty, value);
                //NotifyPropertyChanged("yMin");
            }
        }

        // Using a DependencyProperty as the backing store for xMax.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty yMinProperty =
            DependencyProperty.Register("yMin", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(-32768, yMinPropertyChangedCallback, yMinPropertyCoerceValueCallback));

        private static void yMinPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(yMinProperty);
            DrawYscale(d as ZKChartUserControl);
            DrawY(d as ZKChartUserControl);
            //if (!(d as ZKChartUserControl).Start)
            //{
            //    (d as ZKChartUserControl).DrawCurve((d as ZKChartUserControl).Auto, true);
            //}
        }

        private static object yMinPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            if (v > Int16.MaxValue)
                v = Int16.MaxValue;
            if (v < Int16.MinValue)
                v = Int16.MinValue;
            if (v > (d as ZKChartUserControl).yMax)
                v = (d as ZKChartUserControl).yMax;
            return v;
        }
        #endregion

        #region xMinDefault (非DependencyProperty，始终为0)

        public readonly int  xMinDefault = 0;
        //{
        //    get { return (int)GetValue(xMinDefaultProperty); }
        //    set { SetValue(xMinDefaultProperty, value); }
        //}

        // Using a DependencyProperty as the backing store for xMinDefault.  This enables animation, styling, binding, etc...
        //public static readonly DependencyProperty xMinDefaultProperty =
        //    DependencyProperty.Register("xMinDefault", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(0,xMinDefaultPropertyChangedCallback,xMinDefaultPropertyCoerceValueCallback));


        //private static void xMinDefaultPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        //{
        //    d.CoerceValue(xMinDefaultProperty);
        //}

        //private static object xMinDefaultPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        //{
        //    //int v = (int)baseValue;
        //    //if (v < (d as ZKChartUserControl).xMin)// 如果小于最小值，则强制设置为最小值
        //    //    v = (d as ZKChartUserControl).xMin;
        //    //if (v > (d as ZKChartUserControl).xMax)// 如果大于最大值，则不改变原值
        //    //    v = (d as ZKChartUserControl).xMinDefault;
        //    //if(v>(d as ZKChartUserControl).xMaxDefault) // 如果大于默认最大值，则同样不改变原值
        //    //    v = (d as ZKChartUserControl).xMinDefault;
        //    int v = 0; // xMinDefault始终是0
        //    return v;
        //}

        #endregion

        #region xMaxDefault

        public int xMaxDefault
        {
            get { return (int)GetValue(xMaxDefaultProperty); }
            set { SetValue(xMaxDefaultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for xMinDefault.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty xMaxDefaultProperty =
            DependencyProperty.Register("xMaxDefault", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(1000, xMaxDefaultPropertyChangedCallback, xMaxDefaultPropertyCoerceValueCallback));


        private static void xMaxDefaultPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(xMaxDefaultProperty);
        }

        private static object xMaxDefaultPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;

            //if (v > (d as ZKChartUserControl).xMax)// 如果大于最大值，则强制设置为最大值 
            //    v = (d as ZKChartUserControl).xMax;
            //if (v < (d as ZKChartUserControl).xMin)// 如果小于最小值，则不改变原值
            //    v = (d as ZKChartUserControl).xMaxDefault;
            if (v < (d as ZKChartUserControl).xMinDefault) // 如果小于默认最小值，则同样不改变原值
                v = (d as ZKChartUserControl).xMaxDefault;
            return v;
        }

        #endregion

        #region yMinDefault

        public int yMinDefault
        {
            get { return (int)GetValue(yMinDefaultProperty); }
            set { SetValue(yMinDefaultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for xMinDefault.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty yMinDefaultProperty =
            DependencyProperty.Register("yMinDefault", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(-32768, yMinDefaultPropertyChangedCallback, yMinDefaultPropertyCoerceValueCallback));


        private static void yMinDefaultPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(yMinDefaultProperty);
        }

        private static object yMinDefaultPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            //if (v < (d as ZKChartUserControl).yMin)// 如果小于最小值，则强制设置为最小值
            //    v = (d as ZKChartUserControl).yMin;
            //if (v > (d as ZKChartUserControl).yMax)// 如果大于最大值，则不改变原值
            //    v = (d as ZKChartUserControl).yMinDefault;
            if (v > (d as ZKChartUserControl).yMaxDefault) // 如果大于默认最大值，则同样不改变原值
                v = (d as ZKChartUserControl).yMinDefault;
            return v;
        }

        #endregion

        #region yMaxDefault

        public int yMaxDefault
        {
            get { return (int)GetValue(yMaxDefaultProperty); }
            set { SetValue(yMaxDefaultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for xMinDefault.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty yMaxDefaultProperty =
            DependencyProperty.Register("yMaxDefault", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(32767, yMaxDefaultPropertyChangedCallback, yMaxDefaultPropertyCoerceValueCallback));


        private static void yMaxDefaultPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(xMaxDefaultProperty);
        }

        private static object yMaxDefaultPropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;

            //if (v > (d as ZKChartUserControl).yMax)// 如果大于最大值，则强制设置为最大值 
            //    v = (d as ZKChartUserControl).yMax;
            //if (v < (d as ZKChartUserControl).yMin)// 如果小于最小值，则不改变原值
            //    v = (d as ZKChartUserControl).yMaxDefault;
            if (v < (d as ZKChartUserControl).yMinDefault) // 如果小于默认最小值，则同样不改变原值
                v = (d as ZKChartUserControl).yMaxDefault;
            return v;
        }

        #endregion
        
        #region xScale
        public int xScale
        {
            get { return (int)GetValue(xScaleProperty); }
            set { SetValue(xScaleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for xScale.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty xScaleProperty =
            DependencyProperty.Register("xScale", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(6, xScalePropertyChangedCallback, xScalePropertyCoerceValueCallback));

        private static void xScalePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(xScaleProperty);
            DrawXscale(d as ZKChartUserControl);
            DrawX(d as ZKChartUserControl);
            //if (!(d as ZKChartUserControl).Start)
            //{
            //    (d as ZKChartUserControl).DrawCurve((d as ZKChartUserControl).Auto, true);
            //}
        }

        private static object xScalePropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            if (v <= 0)
                v = 1;
            return v;
        }

#endregion

        #region yScale
        public int yScale
        {
            get { return (int)GetValue(yScaleProperty); }
            set { SetValue(yScaleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for yScale.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty yScaleProperty =
            DependencyProperty.Register("yScale", typeof(int), typeof(ZKChartUserControl), new PropertyMetadata(50, yScalePropertyChangedCallback, yScalePropertyCoerceValueCallback));

        private static void yScalePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(yScaleProperty);
            DrawYscale(d as ZKChartUserControl);
            DrawY(d as ZKChartUserControl);
            //if (!(d as ZKChartUserControl).Start)
            //{
            //    (d as ZKChartUserControl).DrawCurve((d as ZKChartUserControl).Auto, true);
            //}
        }
        private static object yScalePropertyCoerceValueCallback(DependencyObject d, object baseValue)
        {
            int v = (int)baseValue;
            if (v <= 0)
                v = 1;
            return v;
        }

        #endregion

        #region Auto
        public bool Auto
        {
            get { return (bool)GetValue(AutoProperty); }
            set { SetValue(AutoProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Auto.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AutoProperty =
            DependencyProperty.Register("Auto", typeof(bool), typeof(ZKChartUserControl), new PropertyMetadata(false, AutoPropertyChangedCallback));

        private static void AutoPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as ZKChartUserControl).DrawCurve((bool)e.NewValue, true);
        }
        #endregion

        #region isGrid
        public bool isGrid
        {
            get { return (bool)GetValue(isGridProperty); }
            set { SetValue(isGridProperty, value); }
        }

        // Using a DependencyProperty as the backing store for isGrid.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty isGridProperty =
            DependencyProperty.Register("isGrid", typeof(bool), typeof(ZKChartUserControl), new PropertyMetadata(true, isGridPropertyChangedCallback));

        private static void isGridPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DrawX(d as ZKChartUserControl);
            DrawY(d as ZKChartUserControl);
        }
        #endregion

        #region ChartMode
        public CHART_MODE ChartMode
        {
            get { return (CHART_MODE)GetValue(ChartModeProperty); }
            set { SetValue(ChartModeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ChartModeProperty =
            DependencyProperty.Register("ChartMode", typeof(CHART_MODE), typeof(ZKChartUserControl), new PropertyMetadata(CHART_MODE.CONTINUITY_MODE));

        #endregion

        #region textString

        public string textString
        {
            get { return (string)GetValue(textStringProperty); }
            set { SetValue(textStringProperty, value); }
        }

        // Using a DependencyProperty as the backing store for textString.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty textStringProperty =
            DependencyProperty.Register("textString", typeof(string), typeof(ZKChartUserControl), new PropertyMetadata(""));
        
        #endregion

        //画纵向格子线
        private static void DrawX(ZKChartUserControl d)
        {

            Line yline;
            Canvas cvs = d.VerGridChart;
            int min = d.xMin;
            int max = d.xMax;
            int scale = d.xScale;
            int index = min;

            
                
            cvs.Children.Clear();
            if (!d.isGrid)
                return;
            System.Windows.Point point = new System.Windows.Point(cvs.ActualWidth, cvs.ActualHeight);
            if (max == min)
                return;
            // 根据最宽字符宽度重新调整scale
            scale = TuneScaleOnWidth(min, max, point.X, scale);

            int nb = (int)Math.Ceiling((max - min + 1) * 1.0 / scale);
            for (int i = 1; i < nb; i++)
            {
                index = i * scale + min;
                yline = new Line();
 
                yline.Stroke = System.Windows.Media.Brushes.LightGray;

                yline.X1 = yline.X2 = (i * scale) * (point.X) / (max - min);

                yline.Y1 = point.Y;
                yline.Y2 = 0;

                if (index < max)
                {
                    int uid = cvs.Children.Add(yline);
                }
            }
        }
        //画横向格子线
        private static void DrawY(ZKChartUserControl d)
        {
            Canvas cvs = d.HorGridChart;
            int min = d.yMin;
            int max = d.yMax;
            int scale = d.yScale;
            int index = min;

            cvs.Children.Clear();
            if (!d.isGrid)
                return;
            if (max == min)
                return;
            System.Windows.Point point = new System.Windows.Point(cvs.ActualWidth, cvs.ActualHeight);
            scale = TuneScaleOnHeight(min, max, point.Y, scale);

            int nb = (int)Math.Ceiling((max - min + 1) * 1.0 / scale);

            for (int i = 1; i < nb; i++)
            {
                index = i * scale + min;
                Line xline = new Line();
                xline.Opacity = 1;
                xline.Stroke = System.Windows.Media.Brushes.LightGray;

                //if (index > max)
                //{  //如果超出范围则对最后一个特殊处理
                //    index = max;
                //    xline.Y1 = xline.Y2 = 0;
                //}
                //else
                    xline.Y1 = xline.Y2 = point.Y - (index - min) * (point.Y) / (max - min);

                xline.X1 = 0;
                xline.X2 = point.X;
                if (index < max)
                {
                    int uid = cvs.Children.Add(xline);
                }
                //if (index == max)
                //    break;
            }
        }
        //基于字符串宽度计算微调后的X轴刻度scale
        private static int TuneScaleOnWidth(int min,int max, double xCvsWidth,int scale)
        {
            TextBlock blk = new TextBlock();
            double charWidth = MeasureTextWidth(max.ToString(), blk.FontSize, blk.FontFamily.ToString());
            if (charWidth > (xCvsWidth) / (max - min) * scale)
                scale = (int)(charWidth / (xCvsWidth / (max - min)));
            return scale;
        }
        //基于字符串高度计算微调后的y轴刻度scale
        private static int TuneScaleOnHeight(int min, int max, double yCvsHeight, int scale)
        {
            TextBlock blk = new TextBlock();
            double charHeight = MeasureTextHeight("123", blk.FontSize, blk.FontFamily.ToString());

            if (charHeight > (yCvsHeight) / (max - min) * scale)
                scale = (int)(charHeight / (yCvsHeight / (max - min)));

            return scale;
        }

        //画X轴刻度线
        private static void DrawXscale(ZKChartUserControl d)
        {
            Line yline;
            TextBlock blk = new TextBlock();
            Canvas cvs = d.BottomCanvas;
            int min = d.xMin;
            int max = d.xMax;
            int scale = d.xScale;

            int index = min;
            cvs.Children.Clear();
            System.Windows.Point point = new System.Windows.Point(cvs.ActualWidth, cvs.ActualHeight);

            // 横线
            yline = new Line();
            yline.Stroke = System.Windows.Media.Brushes.Black;
            yline.X1 = d.LeftCanvas.ActualWidth;
            yline.X2 = point.X - d.RightCanvas.ActualWidth;
            yline.Y1 = yline.Y2 = 2;

            cvs.Children.Add(yline);

            if (max == min)
                return;

            // 根据最宽字符宽度重新调整scale
            scale = TuneScaleOnWidth(min, max, point.X - d.LeftCanvas.ActualWidth - d.RightCanvas.ActualWidth, scale);

            int nb = (int)Math.Ceiling((max - min + 1) * 1.0 / scale);
            for (int i = 0; i < nb + 1; i++)
            {
                index = i * scale + min;
                yline = new Line();
                yline.Stroke = System.Windows.Media.Brushes.Black;

                if (index > max)
                {  //如果超出范围则对最后一个特殊处理
                    index = max;
                    yline.X1 = yline.X2 = point.X - d.RightCanvas.ActualWidth;
                }
                else
                    yline.X1 = yline.X2 = (i * scale) * (point.X - d.LeftCanvas.ActualWidth - d.RightCanvas.ActualWidth) / (max - min) + d.LeftCanvas.ActualWidth;// (point.X - lefmargin) / (len-1)表示每1刻度的间隔宽度

                yline.Y1 = 2;
                yline.Y2 = 10;

                cvs.Children.Add(yline);


                blk = new TextBlock();

                blk.FontSize = 10;
                blk.Text = index.ToString();
                blk.SetValue(Canvas.TopProperty, yline.Y2 + 5);

                blk.SetValue(Canvas.LeftProperty, yline.X1 - MeasureTextWidth(blk.Text, blk.FontSize, blk.FontFamily.ToString()) / 2);

                cvs.Children.Add(blk);

                if (index == max)
                    break;

            }
        }
        //画Y轴刻度线
        private static void DrawYscale(ZKChartUserControl d)
        {// 画Y轴刻度
            Line xline;
            TextBlock blk = new TextBlock();
            Canvas cvs = d.LeftCanvas;
            int min = d.yMin;
            int max = d.yMax;
            int scale = d.yScale;
            int index = min;
            cvs.Children.Clear();
            System.Windows.Point point = new System.Windows.Point(cvs.ActualWidth, cvs.ActualHeight);
            
            // 竖线
            xline = new Line();
            xline.Stroke = System.Windows.Media.Brushes.Black;
            xline.X1 = xline.X2 = point.X - 2;
            xline.Y1 = 0;
            xline.Y2 = point.Y;
            cvs.Children.Add(xline);

            if (min == max)
                return;

            scale = TuneScaleOnHeight(min, max, point.Y, scale);
            // 横向刻度
            int nb = (int)Math.Ceiling((max - min + 1) * 1.0 / scale);
            for (int i = 0; i < nb+1; i++)
            {
                index = i * scale + min;
                xline = new Line();
                xline.Stroke = System.Windows.Media.Brushes.Black;

                xline.X1 = 0 + point.X-10;
                //xline.Y1 = i * (point.Y - 2 * topbuttommargin) / 10 + topbuttommargin;

                xline.X2 = point.X - 2;

                if (index > max)
                {  //如果超出范围则对最后一个特殊处理
                    index = max;
                    xline.Y1 = xline.Y2 = 0;
                }
                else
                    xline.Y1 = xline.Y2 = point.Y - (index-min) * (point.Y) / (max - min);

   

                cvs.Children.Add(xline);

                blk = new TextBlock();

                blk.Text = index.ToString();
                blk.Foreground = System.Windows.Media.Brushes.Black;
                blk.FontSize = 10;
                blk.SetValue(Canvas.TopProperty, xline.Y1 - MeasureTextHeight(blk.Text, blk.FontSize, blk.FontFamily.ToString())/2);
                cvs.Children.Add(blk);
                if (index == max)
                    break;
            }             
        }

        // 计算字符串宽度
        private static double MeasureTextWidth(string text, double fontSize, string fontFamily)
        {
            FormattedText formattedText = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(fontFamily.ToString()), fontSize, Brushes.Black);
            
            return formattedText.WidthIncludingTrailingWhitespace;
        }
        // 计算字符串高度
        private static double MeasureTextHeight(string text, double fontSize, string fontFamily)
        {
            FormattedText formattedText = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(fontFamily.ToString()), fontSize, Brushes.Black);

            return formattedText.Height;
        }

        //构建的XY坐标系中的坐标转换为界面坐标系
        private System.Windows.Point XYTransf(System.Windows.Point point, System.Windows.Point xypoint)//point 变量点，xypoint 构建的坐标原点在屏幕坐标的位置，返回值为构建坐标的点在屏幕坐标的位置
        {
            point.X += xypoint.X;
            point.Y = xypoint.Y - point.Y;

            return point;//显示屏幕坐标系的位置
        }
        // 画连线
        private StreamGeometry BuildRegularPolygon(System.Windows.Point[] values, bool isClosed, bool isfilled)
        {
            // c is the center, r is the radius,
            // numSides the number of sides, offsetDegree the offset in Degrees.
            // Do not add the last point.

            StreamGeometry geometry = new StreamGeometry();

            using (StreamGeometryContext ctx = geometry.Open())
            {
                ctx.BeginFigure(values[0], isfilled /* is filled */, isClosed /* is closed */);

                for (int i = 1; i < values.Length; i++)
                {
                    ctx.LineTo(values[i], true /* is stroked */, false /* is smooth join */);
                }
            }

            return geometry;

        }

        //对单个list进行计算最大最小值
        private void AutoYRange(List<int> dotlist)
        {
            ArrayList list;
            int minTemp, maxTemp;

            if (dotlist.Count == 0)
                return;

            int xMaxIndex = xMax>dotlist.Count-1?dotlist.Count-1: xMax ;
            if (xMaxIndex - xMin + 1 <= 0)
                return;

            int[] copylist = new int[xMaxIndex - xMin + 1];
            dotlist.CopyTo(xMin, copylist, 0, xMaxIndex - xMin + 1);

            list = new ArrayList(copylist);
            list.Sort();

            minTemp = Convert.ToInt32(list[0]);
            maxTemp = Convert.ToInt32(list[list.Count - 1]);
            minmaxList.Add(minTemp);
            minmaxList.Add(maxTemp);
            minmaxList.Sort();

            yMin = yMinData = Convert.ToInt32(minmaxList[0]);
            yMax = yMaxData = Convert.ToInt32(minmaxList[minmaxList.Count - 1]);
            if (yMin == yMax)
            {
                yMin -= 10;
                yMax += 10;
                yMinData = yMin;
                yMaxData = yMax;
            }
        }
        
        //画整体曲线
        private void DrawCurve(bool bAuto, bool bForce)
        {
            System.Windows.Point point = new System.Windows.Point(Linechart.ActualWidth, Linechart.ActualHeight);
            System.Windows.Point xypoint = new System.Windows.Point(0, point.Y);//新坐标原点,左下角

            Linechart.Children.Clear();

            if (chDataList == null)
                return;

            // 自动调整情况下,计算最大最小值

            minmaxList.Clear();
            if (ChartMode == CHART_MODE.CONTINUITY_MODE)
            {
                if (Start)
                {// 如果是在运行过程中，则需要执行删除老数据操作.否则认为是放大缩小操作
                    for (int j = 0; j < chDataList.Count; j++)
                    {
                        if (chDataList[j].dotlist.Count > (xMax - xMin + 1))
                        {//删除老数据
                            chDataList[j].dotlist.RemoveRange(0, chDataList[j].dotlist.Count - ((xMax - xMin + 1)));

                            if (bAuto && chDataList[j].isDraw && !bForce)
                            {
                                // 只有在队列有删除情形下，重新计算最大最小值
                                AutoYRange(chDataList[j].dotlist);
                            }
                        }
                    }
                }
                else
                    bForce = true;// 放大缩小操作下，bForce强制为true
                        
                if (bAuto && bForce)
                {// 强制执行最大最小值计算
                    for (int j = 0; j < chDataList.Count; j++)
                    {
                        if (chDataList[j].isDraw)
                        {
                            // 重新计算最大最小值
                            AutoYRange(chDataList[j].dotlist);
                        }
                    }
                }
                         
            }
            if (ChartMode == CHART_MODE.BLOCK_MODE)
            {
                if (Start)
                {// 如果是在运行过程中，则需要执行删除老数据操作.否则认为是放大缩小操作
                    for (int j = 0; j < chDataList.Count; j++)
                    {
                        if (chDataList[j].dotlist.Count > 2 * (xMaxDefault - xMinDefault + 1))
                        {

                            chDataList[j].dotlist.RemoveRange(0, (xMaxDefault - xMinDefault + 1));
                            if (bAuto && chDataList[j].isDraw && !bForce)
                            {
                                // 只有在队列有删除情形下，重新计算最大最小值
                                AutoYRange(chDataList[j].dotlist);
                            }
                        }
                        if (chDataList[j].dotlist.Count < (xMax - xMin + 1))
                        {
                            continue;
                        }
                    }
                }
                else
                    bForce = true;// 放大缩小操作下，bForce强制为true
                if (bAuto && bForce)
                {// 强制执行最大最小值计算
                    for (int j = 0; j < chDataList.Count; j++)
                    {
                        if (chDataList[j].isDraw)
                        {
                            // 重新计算最大最小值
                            AutoYRange(chDataList[j].dotlist);
                        }
                    }
                }
            }


            // 准备所有曲线的点
            int xMaxIndex;
            int dotsNumb=0;
            for (int j = 0; j < chDataList.Count; j++)
            {
                if (chDataList[j].isDraw == false)
                    continue;
                if (ChartMode == CHART_MODE.CONTINUITY_MODE)
                {
                    xMaxIndex = xMax > chDataList[j].dotlist.Count - 1 ? chDataList[j].dotlist.Count - 1 : xMax;
                    dotsNumb = chDataList[j].dotlist.Count > (xMaxIndex - xMin + 1) ? (xMaxIndex - xMin + 1) : chDataList[j].dotlist.Count;
                    if (dotsNumb <= 0)
                        continue;
                }
                if (ChartMode == CHART_MODE.BLOCK_MODE)
                {
                    if (Start)
                    {
                        if (chDataList[j].dotlist.Count < xMaxDefault - xMinDefault + 1)
                            continue;
                        dotsNumb = xMax < xMaxDefault ? xMax - xMin+1 : xMaxDefault - xMin+1;
                    }
                    else
                    {
                        xMaxIndex = xMax > chDataList[j].dotlist.Count - 1 ? chDataList[j].dotlist.Count - 1 : xMax;
                        dotsNumb = chDataList[j].dotlist.Count > (xMaxIndex - xMin + 1) ? (xMaxIndex - xMin + 1) : chDataList[j].dotlist.Count;
                        if (dotsNumb <= 0)
                            continue; 
                    }
                }
                System.Windows.Point[] points = new System.Windows.Point[dotsNumb];
                for (int i = 0; i < dotsNumb; i++)
                {
                    points[i].X = i * (point.X) * (1.0 / (xMax - xMin));
                    //if(ChartMode == CHART_MODE.BLOCK_MODE)
                        points[i].Y = (chDataList[j].dotlist[i + xMin] - yMin) * (point.Y) / (yMax - yMin);
                    //else
                    //    points[i].Y = (chDataList[j].dotlist[i] - yMin) * (point.Y) / (yMax - yMin);
                    points[i] = XYTransf(points[i], xypoint);
                }

                System.Windows.Shapes.Path myPath = new System.Windows.Shapes.Path();
                myPath.Stroke = chDataList[j].Hbrsh;
                myPath.StrokeThickness = 1.5;
                StreamGeometry theGeometry = BuildRegularPolygon(points, false, false);
                // Create a StreamGeometry to use to specify myPath.
                theGeometry.FillRule = FillRule.EvenOdd;

                // Freeze the geometry (make it unmodifiable)
                // for additional performance benefits.
                theGeometry.Freeze();

                // Use the StreamGeometry returned by the BuildRegularPolygon to 
                // specify the shape of the path.
                myPath.Data = theGeometry;

                // Add path shape to the UI.
                int uid = Linechart.Children.Add(myPath);
 
            }

        }

        private void OnHorGirdChartSizeChanged(object sender, SizeChangedEventArgs e)
        {
            DrawY(this);
        }
        private void OnVerGirdChartSizeChanged(object sender, SizeChangedEventArgs e)
        {
            DrawX(this);
        }

        private void OnLeftCVSChanged(object sender, SizeChangedEventArgs e)
        {
            DrawYscale(this);
        }

        private void OnBottomCVSChanged(object sender, SizeChangedEventArgs e)
        {
            DrawXscale(this);
        }

        private void OnClickMenuReturnToOriginal(object sender, RoutedEventArgs e)
        {
            xMin = xMinDefault;
            xMax = xMaxDefault;
            yMin = yMinDefault;
            yMax = yMaxDefault;
            DrawCurve(Auto, true);
        }

        //private void OnXMinChanged(object sender, MouseButtonEventArgs e)
        //{
        //    MessageBox.Show(xMin.ToString());
        //}

        private void OnXMinChanged(object sender, RoutedPropertyChangedEventArgs<decimal> e)
        {
            //MessageBox.Show(xMin.ToString());
            if(!Start)
                DrawCurve(Auto, true);
        }

        private void OnXMaxChanged(object sender, RoutedPropertyChangedEventArgs<decimal> e)
        {
            if (!Start)
                DrawCurve(Auto, true);
        }

        private void OnYMinChanged(object sender, RoutedPropertyChangedEventArgs<decimal> e)
        {
            if (!Start&&!Auto)
                DrawCurve(Auto, true);
        }

        private void OnYMaxChanged(object sender, RoutedPropertyChangedEventArgs<decimal> e)
        {
            if (!Start&&!Auto)
                DrawCurve(Auto, true);
        }

    }

    // 曲线数据
    public class ChartData
    {
        public List<int> dotlist { get; set; }                 // 曲线数据
        public bool isDraw { get; set; }
        public Brush Hbrsh { get; set; }

        public ChartData(int[] data, Brush brsh, bool bdraw)
        {
            //for (int i = 0; i < data.Length; i++)
            //    dotlist.Add(data[i]);
            dotlist = new List<int>(data);
            isDraw = bdraw;
            Hbrsh = brsh;
        }

        public ChartData(List<int> data, Brush brsh, bool bdraw)
        {
            dotlist = new List<int>(data);
            isDraw = bdraw;
            Hbrsh = brsh;
        }
    }

}
